#include <algorithm>
#include <string>
#include "CarHire.h"
#include "FunctorsCarHire.h"

void CarHire::Add(ICar * car){
	if (car == 0){
		throw std::exception("invalid pointer of type ICar");
	}
	//a new car is always available -> add to list of available cars
	mAvailableCars.push_back(car);
}

void CarHire::PrintAvailable(std::ostream &stream){
	stream << "AVAILABLE CARS:";
	//message if no cars in this list
	if (mAvailableCars.begin() == mAvailableCars.end()){
		stream << " no cars available" << std::endl << std::endl;
		return;
	}
	stream << std::endl;
	//call PrintCars() for every car in the available list
	//all information about a Car is printed
	std::for_each(mAvailableCars.begin(), mAvailableCars.end(), PrintCars(stream));
	stream << std::endl;
}

void CarHire::PrintReserved(std::ostream &stream){
	stream << "RESERVED CARS:";
	//message if no cars in this list
	if (mReservedCars.begin() == mReservedCars.end()){
		stream << " no cars reserved" << std::endl << std::endl;
		return;
	}
	stream << std::endl;
	//call PrintCars() for every car in the reserved list
	//all information about a Car is printed
	std::for_each(mReservedCars.begin(), mReservedCars.end(), PrintCars(stream));
	stream << std::endl;
}

TCars CarHire::GetAvailable(std::string const& type, std::string const& manufacturer){
	//new object of a functor for retrieving all cars matching type and manufacturer
	GetCars availcars(manufacturer, type);
	//search every element in the list of availabe cars for matching information
	availcars = std::for_each(mAvailableCars.begin(), mAvailableCars.end(), availcars);
	return availcars.GetCarList();
}

TCars CarHire::GetReserved(std::string const& type, std::string const& manufacturer){
	//new object of a functor for retrieving all cars matching type and manufacturer
	GetCars reservedcars(manufacturer, type);
	//search every element in the list of reserved cars for matching information
	reservedcars = std::for_each(mReservedCars.begin(), mReservedCars.end(), reservedcars);
	return reservedcars.GetCarList();
}

void CarHire::Reserve(ICar * car){
	if (car == 0){
		throw std::exception("invalid pointer of type ICar");
	}
	//get an iterator on the searched car
	TCarsIter foundcar = std::find(mAvailableCars.begin(), mAvailableCars.end(), car);
	//car is found if the iterator does not point to the end of the list
	if (foundcar != mAvailableCars.end()){
		//add the car to the list of reserved cars
		mReservedCars.push_back(*foundcar);
		//remove it from the list of available cars
		mAvailableCars.remove(*foundcar);
	}
}

void CarHire::MoveToAvailable(ICar * car){
	if (car == 0){
		throw std::exception("invalid pointer of type ICar");
	}
	//get an iterator on the searched car
	TCarsIter foundcar = std::find(mReservedCars.begin(), mReservedCars.end(), car);
	//car is found if the iterator does not point to the end of the list
	if (foundcar != mReservedCars.end()){
		//add the car to the list of available cars
		mAvailableCars.push_back(*foundcar);
		//remove it from the list of reserved cars
		mReservedCars.remove(*foundcar);
	}
}